package com.jyw.business.obstacles.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.google.common.collect.Lists;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.jyw.business.obstacles.constant.*;
import com.jyw.business.obstacles.domain.*;
import com.jyw.business.obstacles.domain.dto.web.*;
import com.jyw.business.obstacles.domain.dto.wechat.WorkOrderQueryDto;
import com.jyw.business.obstacles.domain.dto.wechat.WxWorkOrderQueryPageDto;
import com.jyw.business.obstacles.domain.dto.wechat.WxWorkOrderReviewPageDto;
import com.jyw.business.obstacles.domain.vo.web.*;
import com.jyw.business.obstacles.domain.vo.wechat.WorkOrderQueryVO;
import com.jyw.business.obstacles.domain.vo.wechat.WxWorkOrderQueryPageVO;
import com.jyw.business.obstacles.domain.vo.wechat.WxWorkOrderReviewPageVO;
import com.jyw.business.obstacles.enums.CompleteTypeEnum;
import com.jyw.business.obstacles.enums.TempEnum;
import com.jyw.business.obstacles.mapper.ObsOrderFaultMapper;
import com.jyw.business.obstacles.mapper.ObsOrderProcessMapper;
import com.jyw.business.obstacles.service.*;
import com.jyw.common.constant.PermissionConstant;
import com.jyw.common.constant.SysDictTypeConstant;
import com.jyw.common.core.domain.entity.SysDictData;
import com.jyw.common.core.page.BasePage;
import com.jyw.common.event.AstMeteringCompleteEvent;
import com.jyw.common.excel.ExportUtils;
import com.jyw.common.excel.ObjectParseUtils;
import com.jyw.common.exception.ServiceException;
import com.jyw.common.exception.base.BaseException;
import com.jyw.common.utils.*;
import com.jyw.common.utils.bean.BeanUtils;
import com.jyw.system.domain.SysDeptIpAddress;
import com.jyw.system.domain.dto.SysOrderAutoDispatchQueryDto;
import com.jyw.system.domain.vo.*;
import com.jyw.system.mapper.SysDeptMapper;
import com.jyw.system.mapper.SysTeamMapper;
import com.jyw.system.service.*;
import com.jyw.system.utils.ConversionUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import static com.jyw.common.utils.SecurityUtils.getUserId;

/**
 * 工单故障Service业务层处理
 *
 * @author system
 * @date 2023-08-10
 */
@Service
@Slf4j
public class ObsOrderFaultServiceImpl extends ServiceImpl<ObsOrderFaultMapper, ObsOrderFault> implements IObsOrderFaultService {

    @Resource
    private ObsOrderFaultMapper obsOrderFaultMapper;

    @Resource
    private IObsOrderInfoService orderInfoService;

    @Resource
    private IObsOrderSendService orderSendService;

    @Resource
    private ISysOrderReviewConfigService orderReviewConfigService;

    @Resource
    private ISysDictDataService sysDictDataService;

    @Resource
    private ObsOrderProcessMapper obsOrderProcessMapper;

    @Resource
    private IObsOrderProcessService processService;

    @Resource
    private IObsOrderMakeService orderMakeService;

    @Resource
    private SysTeamMapper sysTeamMapper;

    @Resource
    private SysDeptMapper sysDeptMapper;

    @Resource
    private ApplicationContext applicationContext;

    @Resource
    private ISysDeptIpAddressService sysDeptIpAddressService;

    @Resource
    private ISysOrderReminderConfigService reminderConfigService;

    @Resource
    private ISysUserTeamService userTeamService;

    @Resource
    private ISysOrderExpectedTimeConfigService expectedTimeConfigService;

    @Resource
    private IObsOrderMessageService obsOrderMessageService;

    @Resource
    private IObsOrderAssistService assistService;

    @Resource
    private ISysOrderAutoDispatchConfigService dispatchConfigService;

    @Resource
    private ISysOrderAutoDispatchService autoDispatchService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ObsOrderInfo add(BaseOrderAddDto addDto) {
        //构建工单信息
        ObsOrderInfo orderInfo = addDto.buildOrder();
        //如果是已经有了工单号那么就是电话建单
        if(!ObjectUtils.isEmpty(addDto.getOrderNum())){
            orderInfo = orderInfoService.getInfoByOrderNum(addDto.getOrderNum());
            //设置报修信息
            orderInfo.setDeptId(addDto.getDeptId());
            orderInfo.setPlace(addDto.getPlace());
            orderInfo.setPhone(addDto.getPhone());
            orderInfo.setUser(addDto.getUser());
            orderInfo.setFaultAddress(addDto.getFaultAddress());
            orderInfo.setCreateOrderFault(1);
            orderInfo.setDealType(OrderDealTypeConstant.CREATE_ORDER);
        }
        // IP地址ID
        List<Long> ipAddressIdList = setIpAddress(addDto.getIpAddressId(),addDto.getDeptId(),addDto.getIpAddress());
        // 转换IP
        if(CollUtil.isNotEmpty(ipAddressIdList)){
            String ipAddressId= JSON.toJSONString(ipAddressIdList);
            orderInfo.setIpAddressId(ipAddressId);
        }
        //如果不存在工单号那么就要生成工单号
        if(ObjectUtils.isEmpty(orderInfo.getOrderNum())){
            //生成工单号
            orderInfo.setOrderNum(orderInfoService.generateOrderNum());
        }
        //保存工单信息
        orderInfoService.saveOrUpdate(orderInfo);
        //创建工单故障
        ObsOrderFault orderFault = addDto.buildOrderFault(orderInfo);
        // 设置期望完成时间
        if (addDto.getCompleteType() != null) {
            setCompleteTime(orderFault, addDto.getCompleteType());
        }
        //记录创建工单流程
        processService.record(OrderProcessRecordDto
                .builder()
                .operState(OrderProcessStateConstant.CREATE_ORDER)
                .orderNum(orderInfo.getOrderNum())
                .processValue(orderFault.getSource().toString()).build());
        //保存故障信息
        save(orderFault);
        //判断是否指定接单人
        if (addDto.canBuildSend()) {
            //兼容小程序多选派单部门
            List<ObsOrderSend> sendList = addDto.buildSend();
            //设置工单号
            ObsOrderInfo finalOrderInfo = orderInfo;
            sendList.forEach(data -> data.setOrderNum(finalOrderInfo.getOrderNum()));
            orderSendService.saveBatch(sendList);
            //批量记录派单
            sendList.forEach(send -> {
                //创建派单流程
                OrderProcessRecordDto sendProcess = OrderProcessRecordDto
                        .builder()
                        .orderNum(finalOrderInfo.getOrderNum())
                        .operState(OrderProcessStateConstant.ALLOCATE)
                        .build();
                BeanUtils.copyProperties(send, sendProcess);
                processService.record(sendProcess);
            });
            //修改工单为待接单
            lambdaUpdate().eq(ObsOrderFault::getId, orderFault.getId()).set(ObsOrderFault::getCurrState, OrderCurrStateConstant.WAIT_ACCEPT).update();
            log.info("创建工单:{},指定接单人,设置工单状态为待接单", orderInfo.getOrderNum());
            if (addDto.getSendType().equals(1)) {
                //如果是由我处理,需要接单
                orderMakeService.receive(new ReceiveOrderDto() {{
                    setOrderNum(finalOrderInfo.getOrderNum());
                }});
            }
        }
        // 判读是否发送集中报修消息
        String faultType=orderFault.getFaultType();
        obsOrderMessageService.centreRepairRemind(faultType);
        //执行自动派单
        autoSend(orderInfo.getOrderNum());
        return orderInfo;
    }

    /**
     * 设置ip地址
     *
     * @param ipAddressIds
     * @param deptId
     * @param ipAddress
     * @return
     */
    private List<Long> setIpAddress(List<Long> ipAddressIds,Long deptId,String ipAddress){
        // IP地址ID
        List<Long> ipAddressIdList = new ArrayList<>();
        if (CollUtil.isNotEmpty(ipAddressIds)) {
            ipAddressIdList.addAll(ipAddressIds);
        }
        // 输入IP
        if (deptId != null && StrUtil.isNotEmpty(ipAddress)) {
            String[] ipAddressArr = ipAddress.split(";");
            Arrays.asList(ipAddressArr).forEach(ip -> {
                        SysDeptIpAddress oldDeptIpAddress = sysDeptIpAddressService.getIpAddress(deptId, ip);
                        if (oldDeptIpAddress == null) {
                            SysDeptIpAddress sysDeptIpAddress = new SysDeptIpAddress();
                            sysDeptIpAddress.setDeptId(deptId);
                            sysDeptIpAddress.setIpAddress(ipAddress);
                            sysDeptIpAddress.setCreateTime(LocalDateTime.now());
                            sysDeptIpAddressService.save(sysDeptIpAddress);
                            ipAddressIdList.add(sysDeptIpAddress.getId());
                        } else {
                            ipAddressIdList.add(oldDeptIpAddress.getId());
                        }
                    }
            );
        }
        return  ipAddressIdList;
    }

    /**
     * 设置期望完成时间
     *
     * @param orderFault
     * @param completeType
     */
    private void setCompleteTime(ObsOrderFault orderFault, int completeType) {
        LocalDate now = LocalDate.now();
        SysOrderExpectedTimeConfigVo configVo=expectedTimeConfigService.getConfig();
        if (completeType == CompleteTypeEnum.MORNING.getValue()) {
            LocalDateTime completeTime;
            if(configVo!=null&&configVo.getMorningEndTime()!=null){
                completeTime = now.atTime(configVo.getMorningEndTime());
            }else{
                completeTime = now.atTime(12, 0, 0);
            }
            orderFault.setCompleteTime(completeTime);
        }
        if (completeType == CompleteTypeEnum.AFTERNOON.getValue()) {
            LocalDateTime completeTime;
            if(configVo!=null&&configVo.getAfternoonEndTime()!=null){
                completeTime = now.atTime(configVo.getAfternoonEndTime());
            }else{
                completeTime = now.atTime(18, 0, 0);
            }
            orderFault.setCompleteTime(completeTime);
        }
        if (completeType == CompleteTypeEnum.TOMORROW.getValue()) {
            LocalDate tomorrow = now.plusDays(1);
            // 明日默认明天12点
            LocalDateTime completeTime = tomorrow.atTime(12, 0, 0);
            orderFault.setCompleteTime(completeTime);
        }
    }

    @Override
    public ObsOrderFault getFaultByOrder(String orderNum) {
        return getOne(new QueryWrapper<ObsOrderFault>().eq(StrUtil.toUnderlineCase(ObsOrderFault.Fields.orderNum), orderNum));
    }

    @Override
    public boolean isAudit(String orderNum, Integer orderSource, String faultType) {
        SysOrderReviewConfigAllVo config = orderReviewConfigService.getConfig();
        //判断是否开启配置
        if (!config.getSysOrderReviewConfig().getIsReview()) {
            return false;
        }
        switch (config.getSysOrderReviewConfig().getReviewMode()) {
            case 1:
                //故障分类,故障来源
                //先检查工单来源
                if (config.getFaultSourceList().stream()
                        .filter(data -> data.getRecordId().equals(orderSource.toString()) && data.getChecked()).findFirst().isPresent()) {
                    return true;
                }
                //检查故障类型
                //查询第一级故障类型
                SysDictData parentFault = sysDictDataService.getTopLevelFaultType(faultType);
                //查询是否开启审核
                if (config.getFaultTypeList().stream().filter(
                        data -> data.getRecordId().equals(parentFault.getDictValue()) && data.getChecked()
                ).findFirst().isPresent()) {
                    return true;
                }
            case 2:
                //人员
                if (config.getStaffList().stream().filter(data -> Long.valueOf(data.getRecordId()).equals(getUserId())).findFirst().isPresent()) {
                    return true;
                }
        }
        //判断审核工单类型
        if(!StringUtils.isEmpty(config.getSysOrderReviewConfig().getReviewOrderType())){
            ObsOrderFault fault = getFaultByOrder(orderNum);
            //循环判断
            for (String orderType : config.getSysOrderReviewConfig().getReviewOrderType().split(",")) {
                //特殊工单
                if(orderType.equals("1")&&!ObjectUtils.isEmpty(fault.getSpecialOrder())){
                    //判断工单是否特殊工单
                    if (fault.getSpecialOrder().equals(1)) {
                        return true;
                    }
                }
                //发起协作的工单(主工单)
                if (orderType.equals("2")&&assistService.lambdaQuery().eq(ObsOrderAssist::getOrderNum,orderNum).count()>0l) {
                    return true;
                }
                //暂停操作的工单
                if(orderType.equals("3")&&processService.lambdaQuery()
                        .eq(ObsOrderProcess::getOrderNum,orderNum)
                        .eq(ObsOrderProcess::getOperState,OrderProcessStateConstant.MAKING)
                        .eq(ObsOrderProcess::getMakeState,OrderMakeTypeConstant.SUSPEND).count()>0
                ){
                    return true;
                }
            }
        }
        return false;
    }

    @Override
    public List<ServerPageVO> serverPage(ServerPageDto pageDto, BasePage page) {
        if(pageDto.getTemp().equals(TempEnum.EVALUATE_RESULT)){
            //评价结果节点,封装评价结果状态数据
            SysOrderReminderConfigVo config = reminderConfigService.getDefaultConfig();
            if(config.getEvaluateResultRemind()&&!ObjectUtils.isEmpty(config.getEvaluateResult())){
                pageDto.getTemp().setEvaluateResultList(Arrays.stream(config.getEvaluateResult().split(",")).map(data->Integer.valueOf(data)).collect(Collectors.toList()));
            }
        }

        if (!ObjectUtils.isEmpty(page)) {
            PageUtils.startPage();
        }
        List<ServerPageVO> list = obsOrderFaultMapper.serverPage(pageDto);


        return ConversionUtil.conversionList(list, ServerPageVO.class);
    }

    @Override
    public List<ServerCallPageVO> serverCallPage(ServerCallPageDto pageDto, BasePage page) {
        if (!ObjectUtils.isEmpty(page)) {
            PageUtils.startPage();
        }
        List<ServerCallPageVO> list = obsOrderFaultMapper.serverCallPage(pageDto);

        return ConversionUtil.conversionList(list, ServerCallPageVO.class);
    }

    @Override
    public List<WorkOrderPageVO> pageWorkOrder(WorkOrderPageDto workOrderPageDto) {
        //判断是否存在查询所有数据的权限
        if (!SecurityUtils.hasPermission(PermissionConstant.Order.Audit.ALL)) {
            List<Long> teamIds = userTeamService.teamLeaderByUserId(getUserId());
            if(!CollectionUtils.isEmpty(teamIds)){
                //是小组组长
                workOrderPageDto.setTeamId(teamIds.stream().map(data->String.valueOf(data)).collect(Collectors.joining(",")));
            }else{
                //非小组组长
                workOrderPageDto.setTeamId("-1");
            }
        }
        PageHelper.startPage(workOrderPageDto.getPageNum(), workOrderPageDto.getPageSize()).reasonable(true);
        List<WorkOrderPageVO> workOrderPageVOS = ConversionUtil.conversionList(this.baseMapper.pageWorkOrder(workOrderPageDto),WorkOrderPageVO.class);
        //判断是否超时完成
        SysOrderExpectedTimeConfigVo config = expectedTimeConfigService.getDefaultConfig();
        workOrderPageVOS.forEach(data->{
            data.setOverTime(0);
            //期望完成时间不为空
            if(!ObjectUtils.isEmpty(data.getCompleteTime())){
                data.setOverTime(DateUtils.addHours(data.getCompleteTime(),config.getTimeoutHour()).compareTo(data.getCompleteDate())<1?1:0);
            }
        });

        return workOrderPageVOS;
    }

    @Override
    public List<OrderDeptRepairPageVO> getHistoryByDeptId(Long deptId) {
        if(deptId!=null){
            List<OrderDeptRepairPageVO> list = this.baseMapper.getHistoryByDeptId(deptId);
            return ConversionUtil.conversionList(list, OrderDeptRepairPageVO.class);
        }
        return Collections.emptyList();
    }

    @Override
    public List<WxWorkOrderReviewPageVO> pageWxProcessWorkOrder(WxWorkOrderReviewPageDto wxWorkOrderReviewPageDto) {
        return this.baseMapper.pageWxProcessWorkOrder(wxWorkOrderReviewPageDto);
    }

    @Override
    public List<WxWorkOrderQueryPageVO> pageWxAllWorkOrder(WxWorkOrderQueryPageDto wxWorkOrderQueryPageDto) {
        return this.baseMapper.pageWxAllWorkOrder(wxWorkOrderQueryPageDto);
    }

    @Override
    public List<ProcessedPageVO> pageProcessed(WorkOrderPageDto workOrderPageDto) {
        workOrderPageDto.setUserId(getUserId());
        return ConversionUtil.conversionList(this.baseMapper.pageProcessed(workOrderPageDto),ProcessedPageVO.class);
    }

    @Override
    @Transactional(rollbackFor = BaseException.class)
    public void enact(String orderNums) {
        try {
            String orderArray[] = orderNums.split(",");
            if (orderArray == null || orderArray.length == 0) {
                throw new BaseException("提交工单号错误");
            }
            for (String orderNum : orderArray) {
                QueryWrapper<ObsOrderFault> queryWrapper = new QueryWrapper<>();
                queryWrapper.eq("order_num", orderNum);
                ObsOrderFault obsOrderFault = this.getOne(queryWrapper);
                if (obsOrderFault == null) {
                    throw new BaseException("未找到工单");
                }
                if (!obsOrderFault.getCurrState().equals(OrderCurrStateConstant.WAIT_AUDIT)) {
                    throw new BaseException("工单不能审核,状态已改！");
                }
                //转交操作流程
                ObsOrderProcess obsOrderProcess = new ObsOrderProcess();
                //工单号
                obsOrderProcess.setOrderNum(orderNum);
                //上次工单状态（待审核）
                obsOrderProcess.setLastFaultState(OrderCurrStateConstant.WAIT_AUDIT);
                //操作类型（审核）
                obsOrderProcess.setOperState(OrderProcessStateConstant.EXAMINE);
                //审核通过
                obsOrderProcess.setProcessValue(OrderExamineStateConstant.END_EXAMINE);
                obsOrderProcess.setCreateTime(new Date());
                obsOrderProcess.setCreateUser(getUserId());
                obsOrderProcessMapper.insert(obsOrderProcess);
                //修改主表状态
                obsOrderFault.setCurrState(OrderCurrStateConstant.WAIT_APPRAISAL);
                obsOrderFault.setUpdateTime(new Date());
                obsOrderFault.setUpdateUser(getUserId());
                this.updateById(obsOrderFault);


                //判断工单来源如果是工单保养,那么进入待评价时,保养续期
                if (obsOrderFault.getSource().equals(OrderSourceConstant.AST_METERING)) {
                    log.info("资产保养完成,发送保养完成事件,资产Id:{}", obsOrderFault.getAssetsId());
                    //保养续期
                    applicationContext.publishEvent(new AstMeteringCompleteEvent(obsOrderFault.getAssetsId()));
                }
            }
        } catch (BaseException e) {
            throw new BaseException("工单通过失败");
        } catch (Exception e) {
            throw new BaseException("工单通过失败");
        }
    }

    @Override
    @Transactional(rollbackFor = BaseException.class)
    public void reject(OrderRejectUpdDto dto) {
        try {
            QueryWrapper<ObsOrderFault> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("order_num", dto.getOrderNum());
            ObsOrderFault obsOrderFault = this.getOne(queryWrapper);
            if (obsOrderFault == null) {
                throw new BaseException("未找到工单");
            }
            if (!obsOrderFault.getCurrState().equals(OrderCurrStateConstant.WAIT_AUDIT)) {
                throw new BaseException("工单不能审核,状态已改！");
            }
            //转交操作流程
            ObsOrderProcess obsOrderProcess = new ObsOrderProcess();
            //工单号
            obsOrderProcess.setOrderNum(dto.getOrderNum());
            //上次工单状态（待审核）
            obsOrderProcess.setLastFaultState(OrderCurrStateConstant.WAIT_AUDIT);
            //操作类型（审核）
            obsOrderProcess.setOperState(OrderProcessStateConstant.EXAMINE);
            //审核通过
            obsOrderProcess.setProcessValue(OrderExamineStateConstant.NO_EXAMINE);
            obsOrderProcess.setCreateTime(new Date());
            obsOrderProcess.setCreateUser(getUserId());
            obsOrderProcessMapper.insert(obsOrderProcess);
            //修改主表状态
            obsOrderFault.setCurrState(OrderCurrStateConstant.NOT_PASS_AUDIT);
            obsOrderFault.setUpdateTime(new Date());
            obsOrderFault.setUpdateUser(getUserId());
            this.updateById(obsOrderFault);
        } catch (BaseException e) {
            throw new BaseException("工单驳回失败");
        }
    }

    @Override
    public List<OrderAllPageVO> pageWholeOrder(OrderAllPageDto dto) {
        List<OrderAllPageVO> list = this.baseMapper.pageWholeOrder(dto);
        return ConversionUtil.conversionList(list, OrderAllPageVO.class);
    }

    @Override
    public void exportProduct(HttpServletResponse response, OrderAllPageDto dto) {
        SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMddHHmmss");
        List<Map<String, String>> listMap = new ArrayList<>();
        String fileName = "工单" + "-" + formatter.format(new Date()) + ".xlsx";
        List<OrderAllPageVO> orderLists = this.baseMapper.pageWholeOrder(dto);
        for (OrderAllPageVO vo : orderLists) {
            Gson gs = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();
            String listStr = gs.toJson(vo);
            OrderAllPageExcelVO excelVO = gs.fromJson(listStr, OrderAllPageExcelVO.class);
            //TODO 等待状态全部完成再修改
            listMap.add(ObjectParseUtils.objectToMap(excelVO));
        }
        try {
            ExportUtils.exportExport(listMap, "excelTemplate/obs_order.xlsx", fileName, response);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void edit(OrderEditDto editDto) {
        //获取工单
        ObsOrderInfo one = orderInfoService.lambdaQuery().eq(ObsOrderInfo::getOrderNum, editDto.getOrderNum()).one();
        if (ObjectUtils.isEmpty(one)) {
            throw new ServiceException("工单不存在");
        }
        //比对
        ObsOrderInfo newInfo = editDto.buildOrder(one);

        Map<String, Map<String, Object>> compareMap = ClassCompareUtil.compareFields(one, newInfo);
        // IP地址ID
        List<Long> ipAddressIdList = setIpAddress(editDto.getIpAddressId(),editDto.getDeptId(),editDto.getIpAddress());
        // 转换IP
        if(CollUtil.isNotEmpty(ipAddressIdList)){
            String ipAddressId= JSON.toJSONString(ipAddressIdList);
            newInfo.setIpAddressId(ipAddressId);
        }
        //修改数据
        orderInfoService.updateById(newInfo);
        //获取故障
        ObsOrderFault oldFault = lambdaQuery().eq(ObsOrderFault::getOrderNum, editDto.getOrderNum()).one();
        if (ObjectUtils.isEmpty(oldFault)) {
            throw new ServiceException("故障不存在");
        }
        //比对
        ObsOrderFault newFault = editDto.buildOrderFault(oldFault);
        compareMap.putAll(ClassCompareUtil.compareFields(oldFault, newFault));
        // 设置期望完成时间
        if (editDto.getCompleteType() != null) {
            setCompleteTime(newFault, editDto.getCompleteType());
        }
        //修改数据
        updateById(newFault);
        //记录流程
        OrderProcessRecordDto processRecordDto = OrderProcessRecordDto
                .builder()
                .orderNum(editDto.getOrderNum())
                .operState(OrderProcessStateConstant.EDIT_ORDER)
                .processValue(JSONObject.toJSONString(compareMap))
                .build();
        processService.record(processRecordDto);
    }

    @Override
    public List<OrderStatisticsVO> statisticsSource(ObsStatisticsBaseQueryDto dto) {
        dto.setDictType(SysDictTypeConstant.OBS_FAULT_SOURCE);
        List<OrderStatisticsVO> statisticsVOList = this.baseMapper.statisticsSource(dto);
        return statisticsVOList;
    }

    @Override
    public List<OrderFaultTypeStatisticsVO> statisticsFaultType(ObsStatisticsBaseQueryDto dto) {
        dto.setDictType(SysDictTypeConstant.OBS_FAULT_TYPE);
        List<OrderFaultTypeStatisticsVO> statisticsVOList = this.baseMapper.statisticsFaultType(dto);
        for (OrderFaultTypeStatisticsVO vo : statisticsVOList) {
            String dictValueByParentId = this.baseMapper.getDictValueByParentId(vo.getId());
            if (dictValueByParentId != null) {
                Integer childTotal = this.baseMapper.getChildTotal(dictValueByParentId);
                vo.setChildTotal(childTotal);
            }
        }
        return statisticsVOList;
    }

    @Override
    public List<OrderStatisticsVO> statisticsDeptRepair(ObsStatisticsBaseQueryDto dto) {
        List<OrderStatisticsVO> statisticsVOList = this.baseMapper.statisticsDeptRepair(dto);
        return statisticsVOList;
    }

    @Override
    public List<OrderStatisticsVO> statisticsEngineer(ObsStatisticsBaseQueryDto dto) {
        List<OrderStatisticsVO> statisticsVOList = this.baseMapper.statisticsEngineer(dto);
        return statisticsVOList;
    }

    @Override
    public List<CommonFaultsCountVO> statisticsCommonFault(ObsStatisticsBaseQueryDto dto) {
        // 获取所有部门子类
        dto.setDeptIds(sysDeptMapper.getDeptChildList(dto.getDeptId()));
        List<CommonFaultsCountVO> statisticsVOList = this.baseMapper.statisticsCommonFault(dto);
        Map<String, List<CommonFaultsCountVO>> classMap = statisticsVOList.stream().collect(Collectors.groupingBy(CommonFaultsCountVO::getDictLabel));
        List<CommonFaultsCountVO> list = new ArrayList<>();
        classMap.forEach((key, value) -> {
            CommonFaultsCountVO countVO = new CommonFaultsCountVO();
            countVO.setDictLabel(key);
            List<CommonFaultsCountVO> listCount = classMap.get(key);
            int num = listCount.stream().mapToInt(CommonFaultsCountVO::getNum).sum();
            countVO.setNum(num);
            countVO.setChild(listCount);
            list.add(countVO);
        });
        return list;
    }

    @Override
    public List<ServiceDeskStatisticsVO> statisticsWork(ObsStatisticsBaseQueryDto dto) {
        // 获取所有部门子类
        dto.setDeptIds(sysDeptMapper.getDeptChildList(dto.getDeptId()));
        List<ServiceDeskStatisticsVO> statisticsVOList = this.baseMapper.statisticsWork(dto);


        return statisticsVOList;
    }

    @Override
    public void exportSource(HttpServletResponse response, ObsStatisticsBaseQueryDto dto) {
        SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMddHHmmss");
        List<Map<String, String>> listMap = new ArrayList<>();
        String fileName = "故障来源" + "-" + formatter.format(new Date()) + ".xlsx";
        List<OrderStatisticsVO> list = this.statisticsSource(dto);
        int total = list.stream().mapToInt(OrderStatisticsVO::getRealityNum).sum();
        for (int i = 0; i < list.size(); i++) {
            Gson gs = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();
            OrderStatisticsVO vo = list.get(i);
            String listStr = gs.toJson(vo);
            ObsStatisticsExcelVO excelVO = gs.fromJson(listStr, ObsStatisticsExcelVO.class);
            excelVO.setSerialNumber(i + 1);
            if (vo.getRealityNum() != null && vo.getRealityNum() != 0) {
                BigDecimal divide = new BigDecimal(vo.getRealityNum()).divide(new BigDecimal(total), 3, RoundingMode.HALF_UP).multiply(new BigDecimal(100));
                DecimalFormat df = new DecimalFormat("##.##");
                String format = df.format(divide);
                excelVO.setProportion(format + "%");
            } else {
                excelVO.setProportion("0%");
            }
            listMap.add(ObjectParseUtils.objectToMap(excelVO));
        }
        //其他参数
        Map<String, Object> map = new HashMap<>();
        map.put("total", "合计");
        map.put("totalNum", total + "");
        if (dto.getStartTime() != null && !dto.getStartTime().equals("")) {
            map.put("title", dto.getStartTime() + "~" + dto.getEndTime() + "故障来源");
        } else {
            map.put("title", "故障来源");
        }
        try {
            ExportUtils.exportExportTrendsTotal(listMap, map, "excelTemplate/obs_source.xlsx", fileName, response);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void exportFaultType(HttpServletResponse response, ObsStatisticsBaseQueryDto dto) {
        SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMddHHmmss");
        List<Map<String, String>> listMap = new ArrayList<>();
        String fileName = "故障分类" + "-" + formatter.format(new Date()) + ".xlsx";
        List<OrderFaultTypeStatisticsVO> list = this.statisticsFaultType(dto);
        int total = list.stream().mapToInt(OrderFaultTypeStatisticsVO::getRealityNum).sum();
        for (int i = 0; i < list.size(); i++) {
            Gson gs = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();
            OrderFaultTypeStatisticsVO vo = list.get(i);
            String listStr = gs.toJson(vo);
            ObsStatisticsExcelVO excelVO = gs.fromJson(listStr, ObsStatisticsExcelVO.class);
            excelVO.setSerialNumber(i + 1);
            if (vo.getRealityNum() != null && vo.getRealityNum() != 0) {
                BigDecimal divide = new BigDecimal(vo.getRealityNum()).divide(new BigDecimal(total), 3, RoundingMode.HALF_UP).multiply(new BigDecimal(100));
                DecimalFormat df = new DecimalFormat("##.##");
                String format = df.format(divide);
                excelVO.setProportion(format + "%");
            } else {
                excelVO.setProportion("0%");
            }
            listMap.add(ObjectParseUtils.objectToMap(excelVO));
        }
        //其他参数
        Map<String, Object> map = new HashMap<>();
        map.put("total", "合计");
        map.put("totalNum", total + "");
        if (dto.getStartTime() != null && !dto.getStartTime().equals("")) {
            map.put("title", dto.getStartTime() + "~" + dto.getEndTime() + "故障分类");
        } else {
            map.put("title", "故障分类");
        }
        try {
            ExportUtils.exportExportTrendsTotal(listMap, map, "excelTemplate/obs_fault_type.xlsx", fileName, response);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void exportDeptRepair(HttpServletResponse response, ObsStatisticsBaseQueryDto dto) {
        SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMddHHmmss");
        List<Map<String, String>> listMap = new ArrayList<>();
        String fileName = "科室报修情况(工单数量)" + "-" + formatter.format(new Date()) + ".xlsx";
        List<OrderStatisticsVO> list = this.statisticsDeptRepair(dto);
        int total = list.stream().mapToInt(OrderStatisticsVO::getRealityNum).sum();
        for (int i = 0; i < list.size(); i++) {
            Gson gs = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();
            OrderStatisticsVO vo = list.get(i);
            String listStr = gs.toJson(vo);
            ObsStatisticsExcelVO excelVO = gs.fromJson(listStr, ObsStatisticsExcelVO.class);
            excelVO.setSerialNumber(i + 1);
            if (vo.getRealityNum() != null && vo.getRealityNum() != 0) {
                BigDecimal divide = new BigDecimal(vo.getRealityNum()).divide(new BigDecimal(total), 3, RoundingMode.HALF_UP).multiply(new BigDecimal(100));
                DecimalFormat df = new DecimalFormat("##.##");
                String format = df.format(divide);
                excelVO.setProportion(format + "%");
            } else {
                excelVO.setProportion("0%");
            }
            listMap.add(ObjectParseUtils.objectToMap(excelVO));
        }
        //其他参数
        Map<String, Object> map = new HashMap<>();
        map.put("total", "合计");
        map.put("totalNum", total + "");
        if (dto.getStartTime() != null && !dto.getStartTime().equals("")) {
            map.put("title", dto.getStartTime() + "~" + dto.getEndTime() + "科室报修情况(工单数量)");
        } else {
            map.put("title", "科室报修情况(工单数量)");
        }
        try {
            ExportUtils.exportExportTrendsTotal(listMap, map, "excelTemplate/obs_dept_repair.xlsx", fileName, response);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void exportEngineer(HttpServletResponse response, ObsStatisticsBaseQueryDto dto) {
        SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMddHHmmss");
        List<Map<String, String>> listMap = new ArrayList<>();
        String fileName = "工程师排名(工单数量)" + "-" + formatter.format(new Date()) + ".xlsx";
        List<OrderStatisticsVO> list = this.statisticsEngineer(dto);
        int total = list.stream().mapToInt(OrderStatisticsVO::getRealityNum).sum();
        for (int i = 0; i < list.size(); i++) {
            Gson gs = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();
            OrderStatisticsVO vo = list.get(i);
            String listStr = gs.toJson(vo);
            ObsStatisticsExcelVO excelVO = gs.fromJson(listStr, ObsStatisticsExcelVO.class);
            excelVO.setSerialNumber(i + 1);
            if (vo.getRealityNum() != null && vo.getRealityNum() != 0) {
                BigDecimal divide = new BigDecimal(vo.getRealityNum()).divide(new BigDecimal(total), 3, RoundingMode.HALF_UP).multiply(new BigDecimal(100));
                DecimalFormat df = new DecimalFormat("##.##");
                String format = df.format(divide);
                excelVO.setProportion(format + "%");
            } else {
                excelVO.setProportion("0%");
            }
            listMap.add(ObjectParseUtils.objectToMap(excelVO));
        }
        //其他参数
        Map<String, Object> map = new HashMap<>();
        map.put("total", "合计");
        map.put("totalNum", total + "");
        if (dto.getStartTime() != null && !dto.getStartTime().equals("")) {
            map.put("title", dto.getStartTime() + "~" + dto.getEndTime() + "工程师排名(工单数量)");
        } else {
            map.put("title", "工程师排名(工单数量)");
        }
        try {
            ExportUtils.exportExportTrendsTotal(listMap, map, "excelTemplate/obs_engineer.xlsx", fileName, response);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public ServerCountVO serverCount(ServerTotalDto totalDto) {
        ServerCountVO result = new ServerCountVO();
        totalDto.setTemp(TempEnum.MANUAL_CREATE);
        result.setManualCreate(obsOrderFaultMapper.serverCount(totalDto));

        totalDto.setTemp(TempEnum.WECHAT_CREATE);
        result.setWechatCreate(obsOrderFaultMapper.serverCount(totalDto));

        totalDto.setTemp(TempEnum.PHONE_CREATE);
        result.setPhoneCreate(obsOrderFaultMapper.serverCount(totalDto));

        totalDto.setTemp(TempEnum.PICKED_UP);
        result.setPickedUp(obsOrderFaultMapper.serverCount(totalDto));

        totalDto.setTemp(TempEnum.MISSED);
        result.setMissed(obsOrderFaultMapper.serverCount(totalDto));

        totalDto.setTemp(TempEnum.WAIT_DELIVERY);
        result.setWaitDelivery(obsOrderFaultMapper.serverCount(totalDto));

        totalDto.setTemp(TempEnum.UNTENITED);
        result.setUntenited(obsOrderFaultMapper.serverCount(totalDto));

        totalDto.setTemp(TempEnum.FIND_SOMEONE);
        result.setFindSomeone(obsOrderFaultMapper.serverCount(totalDto));

        totalDto.setTemp(TempEnum.END_PHONE);
        result.setEndPhone(obsOrderFaultMapper.serverCount(totalDto));

        totalDto.setTemp(TempEnum.WAIT_ACCEPT);
        result.setWaitAccept(obsOrderFaultMapper.serverCount(totalDto));

        totalDto.setTemp(TempEnum.PROCESSING);
        result.setProcessing(obsOrderFaultMapper.serverCount(totalDto));

        totalDto.setTemp(TempEnum.WAIT_AUDIT);
        result.setWaitAudit(obsOrderFaultMapper.serverCount(totalDto));

        totalDto.setTemp(TempEnum.TRANSFORM);
        result.setTransform(obsOrderFaultMapper.serverCount(totalDto));

        totalDto.setTemp(TempEnum.TERMINATED);
        result.setTerminated(obsOrderFaultMapper.serverCount(totalDto));

        totalDto.setTemp(TempEnum.SUSPENDED);
        result.setSuspended(obsOrderFaultMapper.serverCount(totalDto));

        totalDto.setTemp(TempEnum.WAIT_APPRAISAL);
        result.setWaitAppraisal(obsOrderFaultMapper.serverCount(totalDto));

        totalDto.setTemp(TempEnum.NOT_PASS_AUDIT);
        result.setNotPassAudit(obsOrderFaultMapper.serverCount(totalDto));

        totalDto.setTemp(TempEnum.ENDED);
        result.setEnded(obsOrderFaultMapper.serverCount(totalDto));


        totalDto.setTemp(TempEnum.CREATE_ORDER);
        result.setCreateOrder(obsOrderFaultMapper.serverCount(totalDto));


        totalDto.setTemp(TempEnum.EVALUATE_RESULT);
        //设置评价结果状态
        if(totalDto.getTemp().equals(TempEnum.EVALUATE_RESULT)){
            //评价结果节点,封装评价结果状态数据
            SysOrderReminderConfigVo config = reminderConfigService.getDefaultConfig();
            if(config.getEvaluateResultRemind()&&!ObjectUtils.isEmpty(config.getEvaluateResult())){
                totalDto.getTemp().setEvaluateResultList(Arrays.stream(config.getEvaluateResult().split(",")).map(data->Integer.valueOf(data)).collect(Collectors.toList()));
            }
        }
        result.setEvaluateResult(obsOrderFaultMapper.serverCount(totalDto));

        return result;
    }

    @Override
    public OrderPrintVO getPrintOrderInfo(Long id) {
        //通过id获取信息
        ObsOrderInfo info = orderInfoService.getById(id);
        if (ObjectUtils.isEmpty(info)) {
            return null;
        }
        //通过工单号获取详情
        OrderDetailVO detail = orderInfoService.detail(info.getOrderNum());

        return detail.buildPrint();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void allocate(AllocateDto dto) {
        ObsOrderFault fault = getFaultByOrder(dto.getOrderNum());
        if (ObjectUtils.isEmpty(fault)) {
            throw new ServiceException("工单不存在");
        }
        if (!Lists.newArrayList(OrderCurrStateConstant.WAIT_DELIVERY, OrderCurrStateConstant.WAIT_ACCEPT).contains(fault.getCurrState())) {
            throw new ServiceException("当前不能派单");
        }
        //查询是否存在派单记录
        //已经派过单了,删除原来的派单记录
        orderSendService.lambdaUpdate().eq(ObsOrderSend::getOrderNum, dto.getOrderNum()).remove();
        //新增派单记录
        ObsOrderSend send = dto.buildSend();
        orderSendService.save(send);
        //修改故障状态为待派单
        lambdaUpdate().eq(ObsOrderFault::getOrderNum, dto.getOrderNum())
                .set(ObsOrderFault::getCurrState, OrderCurrStateConstant.WAIT_ACCEPT).update();
        //创建派单流程
        OrderProcessRecordDto sendProcess = OrderProcessRecordDto
                .builder()
                .lastFaultState(fault.getCurrState())
                .orderNum(dto.getOrderNum())
                .operState(OrderProcessStateConstant.ALLOCATE)
                .build();
        BeanUtils.copyProperties(send, sendProcess);
        processService.record(sendProcess);
    }

    @Override
    public List<WorkOrderQueryVO> listWeChatOrder(WorkOrderQueryDto dto) {
        //小组
        List<Long> teamList = new ArrayList<>();
        //用户
        List<Long> userList = new ArrayList<>();
        //查询自己的
        userList.add(getUserId());
        //查询自己对应的组的
        if (userList.size() > 0) {
            for (Long userId : userList) {
                List<Long> teamsList = sysTeamMapper.getTeamList(userId);
                for (Long teamId : teamsList) {
                    if (!teamList.contains(teamId)) {
                        teamList.add(teamId);
                    }
                }
            }
        }
        dto.setUserList(userList);
        dto.setTeamList(teamList);
        PageHelper.startPage(dto.getPageNum(), dto.getPageSize()).reasonable(true);
        List<WorkOrderQueryVO> listWeChatOrder = this.baseMapper.listWeChatOrder(dto);
        return listWeChatOrder;
    }

    @Override
    public List<LinkOrderVO> linkOrder(String phone) {
        List<LinkOrderVO> list = obsOrderFaultMapper.linkOrder(phone);
        list.forEach(data -> data.processMakeUser());
        return ConversionUtil.conversionList(list, LinkOrderVO.class);
    }

    @Override
    public Long getMakeTimeSec(String orderNum) {
        return obsOrderFaultMapper.getMakeTimeSec(orderNum);
    }

    /**
     * 自动派单
     * @param orderNum
     */
    private void autoSend(String orderNum){
        //获取配置
        SysOrderAutoDispatchConfigVo config = dispatchConfigService.getDefaultConfig();
        //是否开启派单
        if(!config.getAutoDispatch()){
            return;
        }
        ObsOrderFault fault = getFaultByOrder(orderNum);
        //判断工单是否为待派单
        if (!fault.getCurrState().equals(OrderCurrStateConstant.WAIT_DELIVERY)) {
            return;
        }
        //声明派单模式优先级
        List<String> mode = Arrays.asList(config.getDispatchMode().split(","));
        //声明派单对象
        AllocateDto dto = null;
        //这里是在做派单模式的排序
        for (String pri : Arrays.asList("P1", "P2")) {
            //判断报修部门是否开启
            if(config.getRepairDepart().equals(pri)&&mode.contains("1")){
                //报修科室开启了,查询配置
                List<SysOrderAutoDispatchVo> sysOrderAutoDispatchVos = autoDispatchService.queryRepairDepartList(new SysOrderAutoDispatchQueryDto());
                //查询工单的报修科室
                ObsOrderInfo info = orderInfoService.getInfoByOrderNum(orderNum);
                SysOrderAutoDispatchVo vo = sysOrderAutoDispatchVos.stream().filter(data -> data.getDeptId().equals(info.getDeptId()) && !ObjectUtils.isEmpty(data.getSendType())).findFirst().orElse(null);
                //配置不为空,找到数据赋值派单对象
                if(!ObjectUtils.isEmpty(vo)){
                    dto = new AllocateDto(vo);
                    break;
                }
            }
            if(config.getFaultType().equals(pri)&&mode.contains("2")){
                //故障分类开启了
                List<SysOrderAutoDispatchVo> sysOrderAutoDispatchVos = autoDispatchService.queryFaultTypeList(new SysOrderAutoDispatchQueryDto());
                SysOrderAutoDispatchVo vo = sysOrderAutoDispatchVos.stream().filter(data -> data.getFaultType().equals(fault.getFaultType()) && !ObjectUtils.isEmpty(data.getSendType())).findFirst().orElse(null);
                if(!ObjectUtils.isEmpty(vo)){
                    dto = new AllocateDto(vo);
                    break;
                }
            }
        }
        //判断派单对象是否为空
        if(!ObjectUtils.isEmpty(dto)){
            dto.setOrderNum(orderNum);
            allocate(dto);
        }
    }
}
